package com.bjnet.castdemo.airplay.imp;

import android.media.AudioManager;
import android.util.Log;
import android.view.Surface;

import com.bjnet.castdemo.DemoApplication;
import com.bjnet.castdemo.event.AirplayUrlPlayEndEvent;
import com.bjnet.cbox.module.ComBuffer;
import com.bjnet.cbox.module.MediaChannel;
import com.bjnet.cbox.module.MediaChannelInfo;

import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;

import tv.danmaku.ijk.media.player.IMediaPlayer;
import tv.danmaku.ijk.media.player.IjkMediaPlayer;

enum PlayerState{
    PLAYER_STATE_UNINIT("UNINIT"),
    PLAYER_STATE_INIT("INIT"),
    PLAYER_STATE_PREPARING("PREPARING"),
    PLAYER_STATE_PREPARED("PREPARED"),
    PLAYER_STATE_STARTED("STARTED"),
    PLAYER_STATE_PAUSED("PAUSED"),
    PLAYER_STATE_RELEASED("RELEASED");

    PlayerState(String desp){
        descp = desp;
    }
    private String descp;

    @Override
    public String toString() {
        return "{" +
                descp +
                '}';
    }
}

/**
 * @package: com.bjnet.screenrenderdemo
 * @data: 2018/6/14
 * @author: DELL
 */
public class AirplayUrlPlayChannel extends MediaChannel {

    private static final String TAG = "UrlPlayChannel";

    private String url;
    private IjkMediaPlayer player;
    private PlayerState playerState;

    private PlayerState ctrlPlayerState;
    private Timer checkPrepareTimer;

    public AirplayUrlPlayChannel(MediaChannelInfo info) {
        super(info);
        this.url = info.getUrlPath();
        this.player = null;
        this.playerState = PlayerState.PLAYER_STATE_UNINIT;
        this.ctrlPlayerState = PlayerState.PLAYER_STATE_STARTED;
        this.checkPrepareTimer = new Timer();
    }

    @Override
    public int getDuation() {
        Log.v(TAG,"getDuration");
        return 7200000;  //2 hours dummy duation.实际应该填写实际播放视频的时长，单位为毫秒
    }

    @Override

    public void pause() {
        Log.i(TAG, "pause: AirplayUrlPlayChannel pause ,channel id:" + getChannelId());
        synchronized (playerState) {
            if (player != null) {
                if (PlayerState.PLAYER_STATE_PAUSED == this.playerState
                        || PlayerState.PLAYER_STATE_STARTED == this.playerState
                        || PlayerState.PLAYER_STATE_PREPARED == this.playerState) {
                    player.pause();
                    setPlayerState(PlayerState.PLAYER_STATE_PAUSED);
                }
            }
        }
        this.ctrlPlayerState = PlayerState.PLAYER_STATE_PAUSED;
    }

    @Override
    public void play() {
        Log.i(TAG, "AirplayUrlPlayChannel play ,channel id:" + getChannelId());
        if (player != null){
            synchronized (playerState) {
                if (PlayerState.PLAYER_STATE_PAUSED == this.playerState
                        || PlayerState.PLAYER_STATE_STARTED == this.playerState
                        || PlayerState.PLAYER_STATE_PREPARED == this.playerState) {
                    player.start();
                    setPlayerState(PlayerState.PLAYER_STATE_STARTED);
                }
            }
        }
        this.ctrlPlayerState = PlayerState.PLAYER_STATE_STARTED;
    }

    @Override
    public void seek(int sec) {
        if (player != null){
            if (PlayerState.PLAYER_STATE_PAUSED == this.playerState
                    || PlayerState.PLAYER_STATE_STARTED == this.playerState
                    || PlayerState.PLAYER_STATE_PREPARED == this.playerState)
            {
                player.seekTo(sec * 1000);
                Log.i(TAG,"AirplayUrlPlayChannel seek:" + sec);
            }
            else
            {
                Log.i(TAG,"AirplayUrlPlayChannel seek:"+sec+" in error state:"+this.playerState.toString());
            }
        }
    }

    @Override
    public int getPts() {
        int pts = 0;
        synchronized (playerState) {
            if (this.player != null){
                if (this.playerState == PlayerState.PLAYER_STATE_STARTED
                        || this.playerState == PlayerState.PLAYER_STATE_PAUSED)
                {
                    pts = (int)this.player.getCurrentPosition();
                }
            }
        }

        if(0 == pts){
            pts = 1;
        }
        return pts;
    }

    public void setPlayerState(PlayerState playerState) {
        if (this.playerState != playerState){
            Log.i(TAG, "setPlayerState: url channel:"+getChannelId()+" playState from "+this.playerState.toString()+" to "+playerState.toString());
            this.playerState = playerState;
        }
    }

    @Override
    public void setSurface(Surface surface) {
        this.surface = surface;
        synchronized (playerState){
            if (playerState == PlayerState.PLAYER_STATE_UNINIT || playerState == PlayerState.PLAYER_STATE_RELEASED) {

            }else {
                if (this.player != null){
                    this.player.setSurface(surface);
                }
            }
        }

        Log.i(TAG, "setSurface surface:"+surface);
    }

    @Override
    public boolean open() {
        //setState(MCState.MC_OPENED);
        Log.d(DemoApplication.TAG,"AirplayUrlPlayChannel open id:"+getChannelId()+" state:"+state);
        setState(MCState.MC_OPENED);

        synchronized (playerState) {
            this.player = new IjkMediaPlayer();
            try {
                player.setDataSource(this.url);
            } catch (IOException e) {
                Log.e(TAG, e.getMessage());
                e.printStackTrace();

                player.release();
                setPlayerState(PlayerState.PLAYER_STATE_RELEASED);
                this.player = null;

                return false;
            }

            this.player.setSurface(this.surface);
            player.setAudioStreamType(AudioManager.STREAM_MUSIC);
            setPlayerState(PlayerState.PLAYER_STATE_INIT);
        }

        this.player.setOnPreparedListener(new IMediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(IMediaPlayer mp) {
                Log.i(TAG, "url channel:" +
                        "" + getChannelId() + " onPrepared ctrlPlayerState:" + ctrlPlayerState.toString());
                synchronized (playerState) {
                    if(PlayerState.PLAYER_STATE_PREPARING == playerState){
                        setPlayerState(PlayerState.PLAYER_STATE_PREPARED);
                        player.start();
                        setPlayerState(PlayerState.PLAYER_STATE_STARTED);
                    }
                }
                if(ctrlPlayerState == PlayerState.PLAYER_STATE_PAUSED){
                    pause();
                }
            }
        });

        this.player.setOnErrorListener(new IMediaPlayer.OnErrorListener() {
            @Override
            public boolean onError(IMediaPlayer mp, int what, int extra) {
                Log.i(TAG, "url channel:" +
                        "" + getChannelId() + " onError what:" + what);
//                synchronized (playerState) {
//                    doReleasePlayer();
//                }
                DemoApplication.APP.getEventBus().post(new AirplayUrlPlayEndEvent(getChannelId(),what));
                return false;
            }
        });

        this.player.setOnCompletionListener(new IMediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(IMediaPlayer mp) {
                Log.i(TAG, "url channel:" +
                        "" + getChannelId() + " onCompletion what:" + mp);
                DemoApplication.APP.getEventBus().post(new AirplayUrlPlayEndEvent(getChannelId(),0));
            }
        });

        synchronized (playerState) {
            if(playerState == PlayerState.PLAYER_STATE_INIT){
                this.player.prepareAsync();
                setPlayerState(PlayerState.PLAYER_STATE_PREPARING);
            }
        }

        this.checkPrepareTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                synchronized (playerState) {
                    if (playerState == PlayerState.PLAYER_STATE_PREPARING){
                        Log.e(TAG, "url channel:" +
                                "" + getChannelId() + " prepare timeout:");

                        doReleasePlayer();
                    }
                }
            }
        },5000);
        return true;
    }

    private void doReleasePlayer(){
        synchronized (playerState) {
            Log.i(TAG, "doReleasePlayer: channnel id:" + getChannelId() + " state:" + playerState.toString());
            switch (this.playerState) {
                case PLAYER_STATE_UNINIT:
                case PLAYER_STATE_RELEASED:
                    break;
                case PLAYER_STATE_INIT:
                case PLAYER_STATE_PREPARING:
                case PLAYER_STATE_PREPARED: {
                    if (this.player != null) {
                        this.player.release();
                        this.player = null;
                        setPlayerState(PlayerState.PLAYER_STATE_RELEASED);
                    }
                }
                break;
                case PLAYER_STATE_STARTED:
                case PLAYER_STATE_PAUSED:
                    if (this.player != null) {
                        this.player.stop();
                        this.player.release();
                        this.player = null;
                        setPlayerState(PlayerState.PLAYER_STATE_RELEASED);
                    }
                    break;
                default:
                    break;
            }
        }
    }


    @Override
    public void close() {

        Log.d(DemoApplication.TAG, "AirplayUrlPlayChannel close id:" + getChannelId() + " state:" + state);
        if (state == MCState.MC_DEAD){
            return;
        }

        setState(MCState.MC_DEAD);
        this.checkPrepareTimer.cancel();

        synchronized (playerState) {
            doReleasePlayer();
        }

//        Handler handler = CastManager.getMgr().getUiHandler();
//        if (handler != null){
//            Message msg = new Message();
//            msg.what = CastManager.MSG_CHANNEL_CLOSED;
//            handler.sendMessage(msg);
//        }
//        else{
//            Log.i(TAG, "close: no handler");
//        }

        Log.d(DemoApplication.TAG, "AirplayUrlPlayChannel close done id:" + getChannelId() + " state:" + state);
    }

    @Override
    public void onFrame(int frameLen, int w, int h) {
        assert false;
    }

    @Override
    public void onAudioFrame(ComBuffer data) {
        assert false;
    }
    @Override
    public ComBuffer reqBuffer(int size) {
        return null;
    }
}
